package com.example.myapplication.network

import android.content.Context
import android.net.ConnectivityManager
import android.net.LinkProperties
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import android.util.Log
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.IOException
import kotlin.jvm.Throws

/**
 * Create by Tanzhenxing on 2025/8/18.
 * Description:
 */
class NetworkRequestHelper(
    context: Context
) {
    private val connectivityManager =
        context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

    fun requestNetwork(transportType: Int, callback: NetworkCallback) {
        val request = NetworkRequest.Builder()
            .addTransportType(transportType)
            .build()
        connectivityManager.requestNetwork(
            request,
            object : ConnectivityManagerNetworkCallback("requestNetwork") {
                override fun onAvailable(network: Network) {
                    super.onAvailable(network)
                    callback.onNetworkRead(network)
                    connectivityManager.unregisterNetworkCallback(this)
                }

                override fun onUnavailable() {
                    super.onUnavailable()
                    callback.onNetworkUnavailable()
                }
            })
    }

    @Throws(Exception::class)
    fun makeRequestOnNetwork(network: Network?, url: String): String {
        val build = OkHttpClient.Builder()
        network?.let {
            build.socketFactory(network.socketFactory)
        }
        val client = build.build()
        val request = Request.Builder()
            .url(url)
            .build()
        val response = client.newCall(request).execute()
        if (!response.isSuccessful) {
            throw IOException("Unexpected code $response")
        }
        return response.body()?.string()!!
    }

    fun switchToMobileData() {
        val request = NetworkRequest.Builder()
            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
            .build()
        connectivityManager.requestNetwork(
            request,
            object : ConnectivityManagerNetworkCallback("switchToMobileData") {
                override fun onAvailable(network: Network) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        connectivityManager.bindProcessToNetwork(network)
                    } else {
                        ConnectivityManager.setProcessDefaultNetwork(network)
                    }
                    connectivityManager.unregisterNetworkCallback(this)
                }
            })
    }

    fun switchToWifiData() {
        val request = NetworkRequest.Builder()
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
            .build()
        connectivityManager.requestNetwork(
            request,
            object : ConnectivityManagerNetworkCallback("switchToWifiData") {
                override fun onAvailable(network: Network) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        connectivityManager.bindProcessToNetwork(network)
                    } else {
                        ConnectivityManager.setProcessDefaultNetwork(network)
                    }
                    connectivityManager.unregisterNetworkCallback(this)
                }
            })
    }
}

private abstract class ConnectivityManagerNetworkCallback(private val label: String = "") :
    ConnectivityManager.NetworkCallback() {
    override fun onAvailable(network: Network) {
        super.onAvailable(network)
        Log.d("NetworkRequestHelper", "$label onAvailable: $network")
    }

    override fun onUnavailable() {
        super.onUnavailable()
        Log.d("NetworkRequestHelper", "$label onUnavailable: ")
    }

    override fun onLost(network: Network) {
        super.onLost(network)
        Log.d("NetworkRequestHelper", "$label onLost: $network")
    }

    override fun onLosing(network: Network, maxMsToLive: Int) {
        super.onLosing(network, maxMsToLive)
        Log.d("NetworkRequestHelper", "$label onLosing: $network, $maxMsToLive")
    }

    override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
        super.onBlockedStatusChanged(network, blocked)
        Log.d("NetworkRequestHelper", "$label onBlockedStatusChanged: $network, $blocked")
    }

    override fun onCapabilitiesChanged(
        network: Network,
        networkCapabilities: NetworkCapabilities
    ) {
        super.onCapabilitiesChanged(network, networkCapabilities)
        Log.d("NetworkRequestHelper", "$label onCapabilitiesChanged: $network")
    }

    override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
        super.onLinkPropertiesChanged(network, linkProperties)
        Log.d("NetworkRequestHelper", "$label onLinkPropertiesChanged: $network")
    }
}

interface NetworkCallback {
    fun onNetworkRead(network: Network)
    fun onNetworkUnavailable()
}